import { isObject, merge, isFunc, BaseErr, errorHandle } from "utils";
import { RequestInterceptor, ResponseInterceptor } from "../interceptor";
import DefaultConfig from "../configuration";
import { requestFunc } from "../req";
import { CancelError } from "../error";

import type { CommonRes } from "@/typings/common";

import type {
    InnerRequestConfig,
    // 请求
    RequestChainItem,
    RequestInterceptorItem,
    // 响应
    ResponsePass,
    ResponseChainItem,
    ResponseInterceptorItem,
    ErrorResponse,
} from "../types/engine.type";

// 基础 请求类
class BaseServer {
    // 基础配置项
    configuration: InnerRequestConfig;
    // 请求拦截器
    requestInterceptor: RequestInterceptor;
    // 响应拦截器
    responseInterceptor: ResponseInterceptor;

    // /*------------------初始化------------------------*/
    constructor(arg?: InnerRequestConfig) {
        // 检查是不是对象, 不是的话, 就不要了
        if (!isObject(arg)) {
            arg = {};
        }

        // 基础数据
        let config: InnerRequestConfig = merge(DefaultConfig, arg);
        // 浅合并
        this.configuration = config;
        // 初始化 拦截器
        this.requestInterceptor = new RequestInterceptor();
        this.responseInterceptor = new ResponseInterceptor();
    }
    // /*------------------子类可重写的方法------------------------*/
    // 自定义的 通用 参数
    customData(): Record<string, any> {
        return {};
    }
    // 自定义的通用 header
    customRequestHeader(): Record<string, string> {
        return {};
    }

    // 调用request
    request(configuration: InnerRequestConfig) {
        // 合并数据
        let totalConfig: InnerRequestConfig = merge(this.configuration, configuration);
        // 数据
        totalConfig.baseData = merge(totalConfig.baseData ?? {}, this.customData());
        // header
        totalConfig.baseHeader = merge(totalConfig.baseHeader ?? {}, this.customRequestHeader());

        // 开始咯
        this._requestProcess(totalConfig);
    }
    /** 发起请求   处理
     * @param {Object} totalConfiguration 配置
     */
    _requestProcess(totalConfiguration: InnerRequestConfig) {
        let that = this;
        // 调用链
        let chain: RequestChainItem[] = [];
        // 请求拦截器
        this.requestInterceptor.forEach(function (item) {
            // 生成function, 扔 数组里
            chain.push(that._createRequestChainFunc(item));
        });
        // 启动 promise
        let promise = Promise.resolve(totalConfiguration);
        while (chain.length) {
            promise = promise.then(chain.shift());
        }
        let { fail, complete } = totalConfiguration || {};
        promise
            .then(function (config) {
                // 请求拦截器  都ok
                // 开始请求
                that._toPassRequest(config);
            })
            .catch(function (err) {
                // 拦截器 出错了
                let error = err as ErrorResponse;
                fail && fail(error);
                complete && complete();
            });
    }
    // 发起请求
    async _toPassRequest(config: InnerRequestConfig) {
        let { fail, complete } = config || {};
        try {
            let { task, response } = await requestFunc(config);
            // 处理 结果拦截器
            this._responseProcess(task, config, response);
        } catch (e) {
            let err = e as BaseErr;
            // 1. 已经取消了
            // 2. 或者 请求 进入了 fail
            fail && fail({ err, config });
            complete && complete();
        }
    }

    // 开始 进行  结果 拦截器
    _responseProcess(task: UniApp.RequestTask | null, config: InnerRequestConfig, res: any) {
        let that = this;
        let chain: ResponseChainItem[] = [];
        this.responseInterceptor.forEach(function (item) {
            chain.push(that._createResponseChainFunc(item));
        });
        let { fail, complete, success } = config || {};
        // 启动promise
        let startResponse: ResponsePass = {
            res: res,
            config: config,
        };
        let promise = Promise.resolve(startResponse);
        while (chain.length) {
            promise = promise.then(chain.shift());
        }
        promise
            .then(function (resPass) {
                // 判断取消问题
                if (resPass.config.cancelToken && resPass.config.cancelToken.hasCanceledFlag) {
                    // 被取消了
                    let reason = resPass.config.cancelToken.reason;
                    fail && fail({ err: new CancelError(reason), config: resPass.config });
                } else {
                    let { readyToResponse } = resPass.config || {};
                    readyToResponse && readyToResponse(resPass);
                    // 返回
                    success && success(resPass);
                }
            })
            .catch(function (err) {
                let error = err as ErrorResponse;
                // 这个 就是 response的拦截器  reject的咯
                // 拦截器 出错了
                fail && fail(error);
                complete && complete();
            });
    }

    // 请求拦截器 链
    _createRequestChainFunc: (item: RequestInterceptorItem) => RequestChainItem = (item) => {
        return async function (config: InnerRequestConfig) {
            let callFuncResult = item.handler(config);
            if (callFuncResult instanceof Promise) {
                try {
                    // 要拦截, 处理 自定义 请求
                    let finalConfig = await callFuncResult;
                    return finalConfig;
                } catch (e) {
                    // 判断错误 是啥
                    if (e instanceof BaseErr) {
                        let err = e as BaseErr;
                        if (isFunc(item.errMsgFormatter)) {
                            let targetErr = item.errMsgFormatter!(err);
                            throw { err: targetErr, config };
                        } else {
                            throw { err, config };
                        }
                    } else {
                        // 转成 通用的error
                        throw {
                            err: errorHandle.insideErr(e),
                            config,
                        };
                    }
                }
            } else {
                // 直接返回
                return callFuncResult;
            }
        };
    };

    // 执行 拦截器
    _responseChainHandler(
        item: ResponseInterceptorItem,
        responsePass: ResponsePass
    ): CommonRes<ResponsePass | Promise<ResponsePass>> {
        try {
            let callFuncResult = item.handler(responsePass);
            return [undefined, callFuncResult];
        } catch (e) {
            if (e instanceof BaseErr) {
                return [e, undefined];
            }
            return [errorHandle.insideErr(e), undefined];
        }
    }

    // 响应拦截器 链
    _createResponseChainFunc: (item: ResponseInterceptorItem) => ResponseChainItem = (item) => {
        let that = this;
        return async function (responsePass: ResponsePass) {
            let handlerResult = that._responseChainHandler(item, responsePass);
            if (handlerResult[0]) {
                let error = handlerResult[0];
                throw { err: error, config: responsePass.config };
            }
            // 判断是不是 promise
            let callFuncResult = handlerResult[1];
            if (callFuncResult instanceof Promise) {
                try {
                    // 要拦截, 处理 自定义 请求
                    let finalConfig = await callFuncResult;
                    return finalConfig;
                } catch (e) {
                    // 判断错误 是啥
                    if (e instanceof BaseErr) {
                        let err = e as BaseErr;
                        if (isFunc(item.errMsgFormatter)) {
                            let targetErr = item.errMsgFormatter!(err);
                            throw { err: targetErr, config: responsePass.config };
                        } else {
                            throw { err, config: responsePass.config };
                        }
                    } else {
                        // 转成 通用的error
                        throw { err: errorHandle.insideErr(e), config: responsePass.config };
                    }
                }
            } else {
                // 直接返回
                return callFuncResult;
            }
        };
    };
}

export default BaseServer;
